/*
    Nios-sim - one simple NIOSII simulator only for personal interest and fun.
    Copyright (C) 2010  chysun2000@gmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef __NIOS_II_H__
#define __NIOS_II_H__

#include <stdio.h>
#include "public.h"

#define NIOS_REG_CNT (32)
#define D_CACHE_SIZE (16 * 1024)
#define I_CACHE_SIZE (16 * 1024)
#define PC_TRACE_CNT (128)

enum {
	NORMAL_MODE = 0x00,
	SINGLE_STEP = 0x01,
	BREAK_MODE = 0x02,
};

struct NIOS_CPU {
	uint32_t gp_regs[NIOS_REG_CNT]; /* default value is 0 */
 	uint32_t ctrl_regs[NIOS_REG_CNT]; /* is defined in Processor Reference Handbook */
	uint32_t pc;
	uint32_t break_pc;
	uint32_t mode;
	uint32_t pc_trace[PC_TRACE_CNT];
	uint32_t trace_index;
};

#define EXCEPTION_HANDLER_ADDR (0x00800020) /* exc_hook, exception handler address */
#define BREAK_HANDLER_ADDRESS  (0x00000000) /* break handler address */

#define OP_R_TYPE 0x3A
#define OP_J_TYPE 0x00

struct i_type_handler {
	uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code);
};

struct r_type_handler{
	uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code);
};

struct j_type_handler{
	uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code);
};

struct custom_type_handler{
	uint32_t (*handler)(struct NIOS_CPU * cpu, uint32_t code);
};

extern struct i_type_handler i_type_handlers[];
extern struct r_type_handler r_type_handlers[];
extern struct j_type_handler j_type_handlers[];

struct i_type_code{
	uint32_t op:6;
	uint32_t imm16:16;
	uint32_t b:5;
	uint32_t a:5;
}__attribute__ ((__packed__));

struct j_type_code{
	uint32_t op:6;
	uint32_t imm26:26;
}__attribute__ ((__packed__));

struct r_type_code{
	uint32_t op:6;
	uint32_t n:5;
	uint32_t opx:6;
	uint32_t c:5;
	uint32_t b:5;
	uint32_t a:5;
}__attribute__ ((__packed__));

#define handler_item(func) {.handler = func}

struct custom_type_code {
	uint32_t op:6;
	uint32_t n:8;
	uint32_t rc:1;
	uint32_t rb:1;
	uint32_t ra:1;
	uint32_t c:5;
	uint32_t b:5;
	uint32_t a:5;
};

enum GP_REG_ALIAS{
	zero = 0,
	at = 1,
	et = 24,
	bt = 25,
	gp = 26,
	sp = 27,
	fp = 28,
	ea = 29,
	ba = 30,
	ra = 31,
};
enum CTRL_REG_ALIAS{
	status = 0,
	estatus,
	bstatus,
	ienable,
	ipending,
	cpuid,
	exception = 7,
	pteaddr,
	tlbacc,
	tlbmisc,
	badaddr = 12,
	config,
	mpubase,
	mpuacc
};



#define MEM_ADDR (0)
#define IO_ADDR (1)

#define PC_INC_NORMAL (0)
#define PC_INC_BY_INSTR (1)

extern uint32_t custom_instr(struct NIOS_CPU * cpu, uint32_t code);
extern void reset_cpu(void);
extern struct NIOS_CPU * get_nios_cpu(void);
extern uint32_t execute(uint32_t code);
extern int32_t get_addr_type(uint32_t addr);
extern uint8_t get_byte(uint32_t addr);
extern void store_byte(uint32_t addr, uint8_t data);
extern uint16_t get_half_word(uint32_t addr);
extern void store_half_word(uint32_t addr, uint16_t data);
extern uint32_t get_word(uint32_t addr);
extern void store_word(uint32_t addr, uint32_t data);
extern uint32_t get_instruct(struct NIOS_CPU * cpu, uint32_t * mem_base, 
								 uint32_t base_addr);
extern void dump_register(struct NIOS_CPU * cpu);
extern void dump_curr_code(uint32_t code);
extern void dump_next_code(struct NIOS_CPU * cpu);
extern void dump_pc(struct NIOS_CPU * cpu);
extern void set_break(struct NIOS_CPU * cpu, char * input);
extern void dump_mem(struct NIOS_CPU * cpu, char * input);
extern uint32_t ascii_to_hex(char * buf, uint32_t buf_len);

#define def_i_type_code struct i_type_code * instr = (struct i_type_code *)&code
#define def_j_type_code struct j_type_code * instr = (struct j_type_code *)&code
#define def_r_type_code struct r_type_code * instr = (struct r_type_code *)&code


/* BIT Definition for Control register */
#define REG_STATUS_PIE 	(0x01)
#define REG_STATUS_EH	(1<<2)

#define CPU_HAS_IRQ (0x01)
#define CPU_HAS_EXCEPTION (0x02)
#define CPU_HAS_NO_EVENT (0)

extern void handle_irq_exception(struct NIOS_CPU * cpu);
extern void clean_ipending(uint32_t mask);
extern void trace_pc(struct NIOS_CPU * cpu);
#endif

